﻿namespace net.zxteam.ZXLexer.ParsingSources
{
	using System;
	using System.Collections.Generic;
	using System.IO;
	using System.Text;
	using System.Runtime.CompilerServices;
	using System.Collections;

	public sealed class EncodingParsingSource : IParsingSource
	{
		private readonly Stream _sourceStream;
		private readonly bool _isOwnStream;
		private uint _indentLevel;
		private bool _isInitPosition; 

		public EncodingParsingSource(Stream sourceStream) : this(sourceStream, Encoding.UTF8) { }

		public EncodingParsingSource(Stream sourceStream, Encoding encoding)
		{
			if (sourceStream == null) throw new ArgumentNullException("sourceStream");
			if (encoding == null) throw new ArgumentNullException("encoding");

			this._isOwnStream = !sourceStream.CanSeek;

			this._sourceStream = this._isOwnStream
				? new Internal.StreamWrapperSeekabilityOverMemoryCache(sourceStream)
				: sourceStream;
		}

		[MethodImpl(MethodImplOptions.Synchronized)]
		public IParsingSourceCheckPoint CreateCheckPoint()
		{
			throw new NotImplementedException();
		}

		[MethodImpl(MethodImplOptions.Synchronized)]
		public void RestoreCheckPoint(IParsingSourceCheckPoint checkPoint)
		{
			throw new NotImplementedException();
		}

		[MethodImpl(MethodImplOptions.Synchronized)]
		public uint Indent()
		{
			if (_indentLevel == uint.MaxValue) throw new InvalidOperationException();

			return ++_indentLevel;
		}

		[MethodImpl(MethodImplOptions.Synchronized)]
		public uint Dedent()
		{
			if (_indentLevel == null) throw new InvalidOperationException();

			return --_indentLevel;
		}

		public ulong Position { get { return (ulong)_sourceStream.Position; } }

		public uint IndentLevel { get { return _indentLevel; } }

		public void Dispose()
		{
			if (this._isOwnStream)
			{
				this._sourceStream.Dispose();
			}
		}

		bool IIterator<byte>.MoveNext()
		{
			if (!_isInitPosition)
			{
				_isInitPosition = true;
				return true;
			}

			return this._sourceStream.ReadByte() != -1;
		}

		byte IIterator<byte>.Current
		{
			get
			{
				if (!_isInitPosition) throw new InvalidOperationException();

				long pos = this._sourceStream.Position;

				int val = this._sourceStream.ReadByte();
				this._sourceStream.Position = pos; // restore position

				return (byte)val;
			}
		}

		char IIterator<char>.Current
		{
			get
			{
				if (!_isInitPosition) throw new InvalidOperationException();

				throw new NotImplementedException();
			}
		}

		bool IIterator<char>.MoveNext()
		{
			if (!_isInitPosition)
			{
				_isInitPosition = true;
				return true;
			}

			return this._sourceStream.ReadByte() != -1;
		}
	}
}
